/*
 * $Id: Playlist.java 381 2008-04-16 07:21:08Z jasta $
 *
 * Copyright (C) 2008 Josh Guilfoyle <jasta@devtcg.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

package org.devtcg.five.music.activity;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.List;

import org.devtcg.five.music.R;
import org.devtcg.five.music.service.IPlaylistMoveListener;
import org.devtcg.five.music.service.IPlaylistService;
import org.devtcg.five.music.util.PlaylistUtil;
import org.devtcg.five.music.widget.ReflectionLayout;
import org.devtcg.five.music.widget.Rotate3dAnimation;
import org.devtcg.five.provider.Five;

import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Animation.AnimationListener;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class Playlist extends Activity
{
	private static final String TAG = "Playlist";

	private IPlaylistService mPlaylist;

	private ViewGroup mContainer;

	private TextView mArtist;
	private TextView mAlbum;
	private TextView mSong;
	private ReflectionLayout mAlbumCover;

	private ImageButton mControlPrev;
	private ImageButton mControlPause;
	private ImageButton mControlNext;

	private View mControlsMore;
	private View mBtnAlbums;
	private View mBtnSimilarArtists;
	private View mBtnSimilarTracks;
	private View mBtnTopTracks;

	private ImageButton mBtnPlaylist;
	private View mPlaylistView;
	private ListView mPlaylistList;
	private TextView mPlaylistListEmpty;
	private boolean mPlaylistShown = false;

	private boolean mPaused = false;

	private long mSongId = -1;
	private long mAlbumId = -1;
	private long mArtistId = -1;

	private static final int MSG_HIDE_CONTROLS_MORE = 0;

	@Override
	public void onCreate(Bundle icicle)
	{
		super.onCreate(icicle);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.playlist);

		mContainer = (ViewGroup)findViewById(R.id.container);
		((ViewGroup)mContainer.getParent()).setKeepAnimations(true);

		mBtnPlaylist = (ImageButton)findViewById(R.id.btn_playlist);
		mPlaylistView = findViewById(R.id.playlist);
		mPlaylistList = (ListView)findViewById(R.id.playlist_list);
		mPlaylistListEmpty = (TextView)findViewById(R.id.playlist_empty);

		mBtnPlaylist.setOnClickListener(mTogglePlaylist);

		mArtist = (TextView)findViewById(R.id.artist_name);
		mAlbum = (TextView)findViewById(R.id.album_name);
		mSong = (TextView)findViewById(R.id.song_name);

		mAlbumCover = (ReflectionLayout)findViewById(R.id.album_cover);
		mAlbumCover.setOnImageTouchListener(mImageTouched);

		View more = findViewById(R.id.controls_more);
		mBtnAlbums = more.findViewById(R.id.btn_albums_by_artist);
		mBtnSimilarArtists = more.findViewById(R.id.btn_similar_artists);
		mBtnSimilarTracks = more.findViewById(R.id.btn_similar_tracks);
		mBtnTopTracks = more.findViewById(R.id.btn_top_tracks_by_artist);
		mControlsMore = more;

		mBtnAlbums.setOnClickListener(mPickAlbum);
		mBtnSimilarArtists.setOnClickListener(mNotImplemented);
		mBtnSimilarTracks.setOnClickListener(mNotImplemented);
		mBtnTopTracks.setOnClickListener(mPickTopTracks);

		View controls = findViewById(R.id.controls);
		mControlPrev = (ImageButton)controls.findViewById(R.id.control_prev);
		mControlPause = (ImageButton)controls.findViewById(R.id.control_pause);
		mControlNext = (ImageButton)controls.findViewById(R.id.control_next);

		mControlPrev.setOnClickListener(mDoPrev);
		mControlPause.setOnClickListener(mDoPauseToggle);
		mControlNext.setOnClickListener(mDoNext);
	}

	private Handler mHandler = new Handler()
	{
		public void handleMessage(Message msg)
		{
			switch (msg.what)
			{
			case MSG_HIDE_CONTROLS_MORE:
				mAlbumCover.hideTopChild();
				break;
			default:
				super.handleMessage(msg);
			}
		}
	};

	private void controlsMoreKeepAlive()
	{
		mHandler.removeMessages(MSG_HIDE_CONTROLS_MORE);
		Message msg = mHandler.obtainMessage(MSG_HIDE_CONTROLS_MORE);
		mHandler.sendMessageDelayed(msg, 3500);		
	}

//	private final OnClickListener mControlsMoreMisclick = new OnClickListener()
//	{
//		public void onClick(View v)
//		{
//			Log.d(TAG, "Mistouch, visibility=" + v.getVisibility());
//			controlsMoreKeepAlive();
//		}
//	};

	private final OnClickListener mImageTouched = new OnClickListener()
	{
		public void onClick(View v)
		{
			try {
				if (mPlaylist != null && mPlaylist.isPlaying() == false)
					return;
			} catch (DeadObjectException e) { finish(); }

			if (mControlsMore.getVisibility() == View.VISIBLE)
			{
				controlsMoreKeepAlive();
				return;
			}

			mAlbumCover.displayTopChild();

			controlsMoreKeepAlive();
		}
	};

	private final OnClickListener mDoPrev = new OnClickListener()
	{
		public void onClick(View v)
		{
			if (mPlaylist == null)
				return;

			int pos;
			
			try { pos = mPlaylist.previous(); }
			catch (DeadObjectException e) { finish(); return; }
			
			if (pos == -1)
			{
				Toast.makeText(Playlist.this, "End of playlist",
				  Toast.LENGTH_SHORT).show();
			}
		}
	};
	
	private final OnClickListener mDoPauseToggle = new OnClickListener()
	{
		public void onClick(View v)
		{
			if (mPlaylist == null)
				return;

			try
			{
				if (mPaused == true)
				{
					mPlaylist.unpause();
					mControlPause.setImageResource(R.drawable.media_playback_pause);
					mPaused = false;
				}
				else
				{
					mPlaylist.pause();
					mControlPause.setImageResource(R.drawable.media_playback_start);
					mPaused = true;
				}
			}
			catch (DeadObjectException e)
			{
				finish();
			}
		}
	};
	
	private final OnClickListener mDoNext = new OnClickListener()
	{
		public void onClick(View v)
		{
			if (mPlaylist == null)
				return;
			
			int pos;
			
			try { pos = mPlaylist.next(); }
			catch (DeadObjectException e) { finish(); return; }
			
			if (pos == -1)
			{
				Toast.makeText(Playlist.this, "End of playlist",
				  Toast.LENGTH_SHORT).show();
			}
		}
	};

	private final OnClickListener mPickAlbum = new OnClickListener()
	{
		public void onClick(View v)
		{
			Uri artist = ContentUris.withAppendedId
			  (Five.Music.Artists.CONTENT_URI, mArtistId);

			startActivity(new Intent(Intent.VIEW_ACTION, artist,
			  Playlist.this, AlbumAndSongList.class));
		}
	};

	private final OnClickListener mPickTopTracks = new OnClickListener()
	{
		public void onClick(View v)
		{
			mNotImplemented.onClick(v);
		}
	};

	private final OnClickListener mNotImplemented = new OnClickListener()
	{
		public void onClick(View v)
		{
			Toast.makeText(Playlist.this, "Sorry, not implemented.",
			  Toast.LENGTH_SHORT).show();
		}
	};

	private void setNotPlaying()
	{
		mSongId = -1;
		mAlbumId = -1;
		mArtistId = -1;

		Log.d(TAG, "*NOT PLAYING*");

		mSong.setText("End of Playlist");
		mArtist.setText("");
		mAlbum.setText("");
		mAlbumCover.setImageResource(R.drawable.not_playing_cover);
	}

	private void setNowPlaying(long songId)
	{
		Log.d(TAG, "setNowPlaying(" + songId + ")");
		
		Uri song = ContentUris.withAppendedId(Five.Music.Songs.CONTENT_URI, songId);

		String[] proj = new String[] {
			Five.Music.Songs.ARTIST_ID, Five.Music.Songs.ALBUM_ID,
			Five.Music.Songs.TITLE, Five.Music.Songs._ID,
		};

		Cursor c = getContentResolver().query(song, proj, null, null, null);

		if (c.count() == 0)
		{
			c.close();
			return;
		}

		c.first();
		mSong.setText(c.getString(2));
		mArtistId = c.getLong(0);
		mAlbumId = c.getLong(1);
		mSongId = c.getLong(3);
		c.close();

		Uri artist = ContentUris.withAppendedId(Five.Music.Artists.CONTENT_URI, mArtistId);
		
		Cursor cArtist = getContentResolver().query(artist,
		  new String[] { "name" }, null, null, null);
		
		cArtist.first();
		mArtist.setText(cArtist.getString(0));
		cArtist.close();

		Uri album = ContentUris.withAppendedId(Five.Music.Albums.CONTENT_URI, mAlbumId);

		Cursor cAlbum = getContentResolver().query(album,
		  new String[] { "artwork_big", "name" }, null, null, null);

		cAlbum.first();
		mAlbum.setText(cAlbum.getString(1));
        String artwork = cAlbum.getString(0);
        cAlbum.close();

        if (artwork != null)
        	mAlbumCover.setImageURI(Uri.parse(artwork));
        else
        	mAlbumCover.setImageResource(R.drawable.lastfm_cover);

//        mAlbumCover.setImageResource(R.drawable.test2);
	}

	private void initUI()
	  throws DeadObjectException
	{
		assert mPlaylist != null;

		if (mPlaylist.isPlaying() == false)
			setNotPlaying();
		else
		{
			int pos = mPlaylist.getPosition();
			setNowPlaying(mPlaylist.getSongAt(pos));
		}

		if (mPlaylist.isPaused() == true)
		{
			mHandler.post(new Runnable() {
				public void run()
				{
					mControlPause.setImageResource
					  (R.drawable.media_playback_start);
					mPaused = true;
				}
			});
		}
	}
	
	public void onResume()
	{
		PlaylistUtil.bindService(this, mConnection);
		super.onResume();
	}
	
	@Override
	public void onStop()
	{
		if (mPlaylist != null)
		{
			try {
				mPlaylist.unregisterOnMoveListener(mPlaylistMoveListener);
			} catch (DeadObjectException e) {}
		}
		
		unbindService(mConnection);
		super.onStop();
	}

	@Override
	public void onDestroy()
	{
		super.onDestroy();
	}

	private final ServiceConnection mConnection = new ServiceConnection()
	{
		public void onServiceConnected(ComponentName name, IBinder service)
		{
			mPlaylist = IPlaylistService.Stub.asInterface(service);

			try {
				initUI();
				mPlaylist.registerOnMoveListener(mPlaylistMoveListener);
			} catch (DeadObjectException e) {}
		}

		public void onServiceDisconnected(ComponentName name)
		{
			mPlaylist = null;
		}
	};
	
	private final IPlaylistMoveListener mPlaylistMoveListener = new IPlaylistMoveListener.Stub()
	{
		public void advance() throws DeadObjectException
		{
			final long songId = mPlaylist.getSongAt(mPlaylist.getPosition());
			assert songId >= 0;

			mHandler.post(new Runnable() {
				public void run() { setNowPlaying(songId); }
			});
		}

		public void jump(int pos) throws DeadObjectException
		{
			final long songId = mPlaylist.getSongAt(pos);
			assert songId >= 0;

			mHandler.post(new Runnable() {
				public void run() { setNowPlaying(songId); }
			});
		}

		public void pause() throws DeadObjectException
		{
			if (mPaused == true)
				return;

			mHandler.post(new Runnable() {
				public void run()
				{
					mControlPause.setImageResource(R.drawable.media_playback_start);
					mPaused = true;
				}
			});
		}

		public void play() throws DeadObjectException
		{
			final long songId = mPlaylist.getSongAt(mPlaylist.getPosition());
			assert songId >= 0;

			mHandler.post(new Runnable() {
				public void run()
				{
					setNowPlaying(songId);

					if (mPaused == true)
					{
						mControlPause.setImageResource(R.drawable.media_playback_pause);
						mPaused = false;
					}
				}
			});
		}

		public void seek(long pos) throws DeadObjectException {}
		public void skip(long offs) throws DeadObjectException {}

		public void stop() throws DeadObjectException
		{
			mHandler.post(new Runnable() {
				public void run() { setNotPlaying(); }
			});
		}
	};

	/* Most of the code below this point was taken from the 3D animation
	 * demo in M5. */
	private final OnClickListener mTogglePlaylist = new OnClickListener()
	{
		public void onClick(View v)
		{
			Toast.makeText(Playlist.this, "Sorry, play queue management has not been implemented.  It's tricky ;)",
			  Toast.LENGTH_LONG).show();

//			if (mPlaylistShown == true)
//				applyRotation(0, 90);
//			else
//			{
//				if (mPlaylist == null)
//					return;
//
//				List tmp;
//
//				try {
//					tmp = mPlaylist.getPlaylist();
//
//					if (tmp == null || tmp.isEmpty() == true)
//					{
//						mPlaylistList.setVisibility(View.GONE);
//						mPlaylistListEmpty.setVisibility(View.VISIBLE);
//					}
//					else
//					{
//						ListAdapter ad = new PlaylistAdapter(Playlist.this, tmp);
//						mPlaylistList.setAdapter(ad);
//
//						mPlaylistList.setVisibility(View.VISIBLE);
//						mPlaylistListEmpty.setVisibility(View.GONE);
//					}
//				} catch (DeadObjectException e) { finish(); return; }
//
//				applyRotation(0, 90);
//			}
		}
	};

	private void applyRotation(float start, float end)
	{
		final float centerX = mContainer.getWidth() / 2.0f;
		final float centerY = mContainer.getHeight() / 2.0f;
		
		final Rotate3dAnimation rot =
		  new Rotate3dAnimation(start, end, centerX, centerY, 310.0f, true);
		
		rot.setDuration(500);
		rot.setFillAfter(true);
		rot.setInterpolator(new AccelerateInterpolator());
		rot.setAnimationListener(new DisplayNextView());

		mContainer.startAnimation(rot);
	}

	private class DisplayNextView implements AnimationListener
	{
		private DisplayNextView()
		{
			
		}
		
		public void onAnimationStart() {}
		public void onAnimationRepeat() {}
		
		public void onAnimationEnd()
		{
			mContainer.post(new SwapViews());
		}
	}
	
	private class SwapViews implements Runnable
	{
		public SwapViews()
		{
			
		}

		public void run()
		{
			final float centerX = mContainer.getWidth() / 2.0f;
			final float centerY = mContainer.getHeight() / 2.0f;
			Rotate3dAnimation rot;

			if (mPlaylistShown == true)
			{
				mPlaylistView.setVisibility(View.GONE);
				mAlbumCover.setVisibility(View.VISIBLE);
				mAlbumCover.requestFocus();
				
				rot = new Rotate3dAnimation(90, 0, centerX, centerY, 310.0f, false);
				mPlaylistShown = false;
			}
			else
			{
				mAlbumCover.setVisibility(View.GONE);
				mPlaylistView.setVisibility(View.VISIBLE);
				mPlaylistView.requestFocus();
				
				rot = new Rotate3dAnimation(90, 0, centerX, centerY, 310.0f, false);
				mPlaylistShown = true;
			}
			
			rot.setDuration(500);
			rot.setFillAfter(true);
			rot.setInterpolator(new DecelerateInterpolator());

			mContainer.startAnimation(rot);
		}
	}
	
	private static class PlaylistAdapter extends BaseAdapter
	{
		private Context mContext;
		private List mQueue;

		public PlaylistAdapter(Context ctx, List queue)
		{
			mContext = ctx;
			mQueue = queue;
		}

		public int getCount()
		{
			return 0;
		}

		public Object getItem(int position)
		{
			return null;
		}

		public long getItemId(int position)
		{
			return 0;
		}

		public View getView(int position, View convertView, ViewGroup parent)
		{
			return null;
		}
	}
}
